/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2023 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "gpio.h"
#include "iwdg.h"
#include "usart.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
//代码写死 不配置
#define USER_ID  0x20 //天邛
#define DTU_ID_1 0x00
#define DTU_ID_0 0x05
#define METER_ID 0x01 //带仓
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#include "nb.h"
#include "dtuconfig.h"
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#define ID1 (0x1FFFF7E8)
#define ID2 (0x1FFFF7EC)
#define ID3 (0x1FFFF7F0)

#define APP_DATA_SIZE 128

uint32_t          DevAddr;
volatile uint8_t  AppDataSize;
uint8_t           AppData[APP_DATA_SIZE];
uint8_t           FramBuff[255]; //up && down buff
volatile uint16_t FrameSize;     //downlink payload size. add by llb@18-9-20 for downlink.

#define NBRxPayLoad     FramBuff
#define NBRxPayLoadSize FrameSize

uint32_t LastBootTime = 0; //reboot every 24h.
uint32_t LastSendTime = 0; //protection:if long time no TX,reboot.
uint32_t LastReadTick = 0;

#define MAIN_VERSION "V1.0.0"

uint32_t TxDoneCnt = 0;
uint32_t TxFaildCnt = 0;
uint32_t TxFaildAllways = 0;

uint8_t (*RadioSend)(uint8_t*, uint16_t) = 0;
uint8_t (*RadioReInit)() = 0;

uint16_t FrameCnt = 0;

#define RUNNING_TIME 600 //10min. if main loop exceed 10min,then watchdog reset.
volatile uint16_t RunningCnt = 0;

#define MAX_MSG_LEN   30
#define MAX_MSG_NUM   10
#define METER_MSG_LEN 20

typedef enum {
    led_idle = 0,
    led_nb_netting,
    led_sys_run
} led_enum;

led_enum led_status = led_idle;

//尖峰电能       FE FE FE FE 68 AA AA AA AA AA AA 68 11 04 33 34 34 33 AF 16 (d1)
//峰电能         FE FE FE FE 68 AA AA AA AA AA AA 68 11 04 33 35 34 33 B0 16 (d1)
//平电能         FE FE FE FE 68 AA AA AA AA AA AA 68 11 04 33 36 34 33 B1 16 (d1)
//谷电能         FE FE FE FE 68 AA AA AA AA AA AA 68 11 04 33 37 34 33 B2 16 (d1) shibai
//瞬时总功率     FE FE FE FE 68 AA AA AA AA AA AA 68 11 04 33 33 36 35 B2 16
//总功率因数     FE FE FE FE 68 AA AA AA AA AA AA 68 11 04 33 33 39 35 B5 16
//A相电压        FE FE FE FE 68 AA AA AA AA AA AA 68 11 04 33 34 34 35 B1 16
//A相电流        FE FE FE FE 68 AA AA AA AA AA AA 68 11 04 33 34 35 35 B2 16
//正向有功总电能 FE FE FE FE 68 AA AA AA AA AA AA 68 11 04 33 33 34 33 AE 16

uint8_t MeterMsgInfo[MAX_MSG_NUM][MAX_MSG_LEN] = {
    { 0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x68, 0x11, 0x04, 0x33, 0x33, 0x36, 0x35, 0xB2, 0x16 },
    { 0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x68, 0x11, 0x04, 0x33, 0x33, 0x39, 0x35, 0xB5, 0x16 },
    { 0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x68, 0x11, 0x04, 0x33, 0x34, 0x34, 0x35, 0xB1, 0x16 },
    { 0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x68, 0x11, 0x04, 0x33, 0x34, 0x35, 0x35, 0xB2, 0x16 },
    { 0xFE, 0xFE, 0xFE, 0xFE, 0x68, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x68, 0x11, 0x04, 0x33, 0x33, 0x34, 0x33, 0xAE, 0x16 }
};

void SoftReset(void)
{
    __set_FAULTMASK(1);
    NVIC_SystemReset();
}

//Return val: 0-send success, 1-send failed
uint8_t SendFrame(void)
{
    uint8_t  i;
    uint32_t sum = 0;

    msg_printf("Send 2 Radio!\r\n");
    LastSendTime = HAL_GetTick();
    FrameCnt++;

    FramBuff[0] = 0;
    FramBuff[1] = USER_ID;
    FramBuff[2] = DTU_ID_1;
    FramBuff[3] = DTU_ID_0;
    FramBuff[4] = METER_ID;
    FramBuff[5] = 0;
    FramBuff[6] = FrameCnt & 0xff; //FCnt
    FramBuff[7] = FrameCnt >> 8;
    FramBuff[8] = 0; //port
    memcpy(FramBuff + 9, AppData, AppDataSize);
    for (i = 0; i < 9 + AppDataSize; i++) {
        sum += FramBuff[i];
    }
    FramBuff[AppDataSize + 9] = sum & 0xFF;
    FramBuff[AppDataSize + 10] = (sum >> 8) & 0xFF;
    FramBuff[AppDataSize + 11] = (sum >> 16) & 0xFF;
    FramBuff[AppDataSize + 12] = (sum >> 24) & 0xFF;
    i = 13 + AppDataSize;

    if (NB_SendFrame(FramBuff, i)) {
        TxDoneCnt++;
        TxFaildAllways = 0;
        msg_printf("TxDoneCnt: %d\r\n", TxDoneCnt);
        i = 0;

        led_status = led_idle;
        for (int cnt = 0; cnt < 3; cnt++) {
            led_net_on();
            HAL_Delay(100);
            led_net_off();
            HAL_Delay(100);
        }
        led_status = led_sys_run;

    } else {
        TxFaildCnt++;
        TxFaildAllways++;
        if (3 == TxFaildAllways) {
            TxFaildAllways = 0;
            msg_printf("TxFaildAllways, reboot\r\n");
            SoftReset();
        }
        msg_printf("TxFaildCnt: %d TxFaildAllways: %d\r\n", TxFaildCnt, TxFaildAllways);
        HAL_Delay(500); //if send failed, led blink longer.
        i = 1;

        led_status = led_idle;
        led_net_off();
        HAL_Delay(1000);
        led_status = led_sys_run;
    }

    return i;
}

uint8_t ReadOneMeter(void)
{
    uint8_t  index, datalen;
    uint8_t  msgnum;
    uint16_t i;
    uint8_t  meterMSGdatalen = 0;

    memset(AppData, 0, sizeof(AppData));

    //1.config interface
    for (msgnum = 0; msgnum < MAX_MSG_NUM; msgnum++) {
        if (MeterMsgInfo[msgnum][0]) {
            //2 send to meter
            led_tx_on();
            DB_UART_RX.flag = 0;
            usart_send_data(&DB_UART, (uint8_t*)&MeterMsgInfo[msgnum][0], METER_MSG_LEN);
            //DEBUG
            msg_printf("Send2meter %u: ", msgnum);
            msg_printf_hex((uint8_t*)&MeterMsgInfo[msgnum][0], METER_MSG_LEN);
            //3.wait response
            i = 0;
            while (!DB_UART_RX.flag && i < 100) {
                HAL_Delay(10);
                i++;
            }
            led_tx_off();
            //4.deal with the response
            datalen = 0;
            if (DB_UART_RX.flag) {
                DB_UART_RX.flag = 0;
                led_rx_on();
                //DEBUG
                msg_printf("RcvMeterData:");
                msg_printf_hex(DB_UART_RX.buff, DB_UART_RX.len);
                //find 0x68
                for (i = 0; i < DB_UART_RX.len; i++) {
                    if (*(DB_UART_RX.buff + i) == 0x68) {
                        break;
                    }
                }
                //FE FE FE FE 68 34 54 00 08 02 22 68 91 08 33 33 34 33 88 39 33 33 11 16
                if (i < DB_UART_RX.len) {
                    index = i + 9;
                    datalen = *(DB_UART_RX.buff + index); //data len
                    index++;
                    if ((datalen + index + 2) <= DB_UART_RX.len) {
                        if (meterMSGdatalen + datalen > APP_DATA_SIZE - 4) {
                            //payload length is bigger than (128-4)
                            datalen = 0;
                            break;
                        }

                        for (i = 0; i < datalen; i++) {
                            AppData[meterMSGdatalen + i + 4] = (uint8_t)(*(DB_UART_RX.buff + index + i) - 0x33);
                        }
                        meterMSGdatalen += datalen;
                    } else {
                        datalen = 0;
                    }
                }
                HAL_Delay(100);
                led_rx_off();
            }
            HAL_Delay(100);
        }
    }

    //if Rx no data.
    if (meterMSGdatalen == 0) {
        return 0;
    }

    AppDataSize = 4 + meterMSGdatalen;

    SendFrame();

    return 1;
}
/* USER CODE END 0 */

/**
 * @brief  The application entry point.
 * @retval int
 */
int main(void)
{
    /* USER CODE BEGIN 1 */
    uint32_t lastTick = 0;
    uint32_t currentTick = 0;
    LastBootTime = 0;
    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick.
   */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_USART1_UART_Init();
    MX_USART2_UART_Init();
    MX_USART3_UART_Init();
    MX_IWDG_Init();
    /* USER CODE BEGIN 2 */
    led_net_off();
    led_rx_off();
    led_tx_off();

    RadioCfgInfo.Paras.NB.IP1 = 117;
    RadioCfgInfo.Paras.NB.IP2 = 60;
    RadioCfgInfo.Paras.NB.IP3 = 157;
    RadioCfgInfo.Paras.NB.IP4 = 137;
    RadioCfgInfo.Paras.NB.Port = 5683;
    RadioCfgInfo.Paras.NB.eDRX = 0;
    RadioCfgInfo.Paras.NB.PSM = 1;

    msg_printf("start...\r\n");

    //NB init
    led_status = led_nb_netting;
    if (NB_ModuleInit()) {
        msg_printf("NB init succed!\r\n");
        NB_SetIndication();
        NB_GetConnectionInfo();
        led_status = led_sys_run;
        ReadOneMeter();
        LastReadTick = currentTick;
    } else {
        msg_printf("NB init failed!\r\n");
        HAL_Delay(10 * 1000);
        SoftReset();
    }

    while (0) {
        ReadOneMeter();
        HAL_Delay(5000);
    }
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    currentTick = HAL_GetTick();
    lastTick = currentTick;
    led_status = led_sys_run;
    while (1) {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
        currentTick = HAL_GetTick();

        if (currentTick - LastReadTick > 5 * 60 * 1000u) {
            LastReadTick = currentTick;
            ReadOneMeter();
        }

        if (currentTick - lastTick > 5000) {
            lastTick = currentTick;
            msg_printf("sys running, ctick %u, lSendtick %u, lReadtick %u\r\n", currentTick, LastSendTime, LastReadTick);
        }

        if ((currentTick > LastSendTime + 2 * 60 * 60 * 1000) || (currentTick > LastBootTime + 24 * 60 * 60 * 1000)) {
            msg_printf("reboot,currentTick %u,LastSendTime %u,LastBootTime %u\r\n", currentTick, LastSendTime, LastBootTime);
            SoftReset();
        }

        if (0) {
            if (DEBUG_UART_RX.flag) {
                DEBUG_UART_RX.flag = 0;
                usart_send_data(&NB_UART, DEBUG_UART_RX.buff, DEBUG_UART_RX.len);
                for (int i = 0; i < 100; i++) {
                    HAL_Delay(10);
                    if (NB_UART_RX.flag) {
                        break;
                    }
                }
                if (NB_UART_RX.flag) {
                    NB_UART_RX.flag = 0;
                    usart_send_data(&DEBUG_UART, NB_UART_RX.buff, NB_UART_RX.len);
                }
            }
        }
    }
    /* USER CODE END 3 */
}

/**
 * @brief System Clock Configuration
 * @retval None
 */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
    RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };

    /** Initializes the RCC Oscillators according to the specified parameters
   * in the RCC_OscInitTypeDef structure.
   */
    RCC_OscInitStruct.OscillatorType =
        RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    RCC_OscInitStruct.LSIState = RCC_LSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }
    /** Initializes the CPU, AHB and APB buses clocks
   */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
        Error_Handler();
    }
}

/* USER CODE BEGIN 4 */

/*! SysTick Handler Callback per 1ms */
void HAL_SYSTICK_Callback(void)
{
    static volatile uint16_t watchdogFeedTime = 0;
    static volatile uint16_t ledTime = 0;

    if (watchdogFeedTime < 1000) {
        watchdogFeedTime++;
    } else {
        watchdogFeedTime = 0;
        HAL_IWDG_Refresh(&hiwdg);
    }

    ledTime++;
    switch (led_status) {
        case led_idle:
            led_net_off();
            break;
        case led_nb_netting:
            if (ledTime < 100) {
                led_net_on();
            } else if (ledTime < 200) {
                led_net_off();
            } else {
                ledTime = 0;
            }
            break;
        case led_sys_run:
            if (ledTime < 500) {
                led_net_on();
            } else if (ledTime < 3000) {
                led_net_off();
            } else {
                ledTime = 0;
            }
            break;
    }
}
/* USER CODE END 4 */

/**
 * @brief  This function is executed in case of error occurrence.
 * @retval None
 */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while (1) {
    }
    /* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t* file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line
     number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
